import json
import os.path
import threading
import time
from concurrent.futures import ThreadPoolExecutor
from multiprocessing import Process

from flask import request

from httpserver.json_flask import JsonFlask
from httpserver.json_response import JsonResponse
from tess_local_simulator.main import start_local_tess_simulator
from httpserver.utils import get_device_id
from utils.redis_utils import send_redis_hset, get_redis_hset, delte_redis_set, send_redis_set

app = JsonFlask(__name__)
# 添加车辆数
platoon = 0
vehicleNum = 0
vehiclePoints = None
status = None

PENDING = 'pending'
SUCCESS = 'success'
ERROR = 'error'

process_car_dict = {}

process_dist = {}
# 限制仿真最大同时运行进程数量为20
max_process_num = 1
# 限制仿真最大超时等待时间为一小时
max_wait_time = 60 * 60

executor = ThreadPoolExecutor(max_workers=20)
@app.route('/wj/startTessngProcess', methods=['Get'])
def startLocalSimulatorPorcess():
    '''
        启动仿真
    '''
    global process_dist
    # 获取仿真配置
    # sim_cfg = request.get_json()
    # print(sim_cfg)
    config_dict = {}
    config_dict['netPath'] = r'net_file\长安大学.tess'
    config_dict['proj'] = '+proj=tmerc +lon_0=108.90575652010739 +lat_0=34.37650478465651 +ellps=WGS84'
    # 打开文件
    with open(r'net_file\params0716.json', 'r') as file:
        data = json.loads(file.read())
        data = {k: v for k, v in data.items()}
        config_dict['scene_dict'] = data
    # 初始化进程群，默认开启max_process_num（20）个进程，等待被域控调用
    delte_redis_set("processInfo")
    for i in range(max_process_num):
        key = str(i)
        config_dict['process_name'] = key
        # key = sim_cfg['dataChannel']
        if len(process_dist.keys()) >= max_process_num:
            return JsonResponse.error("正在运行的仿真程序超过最大进程数，请稍等重试", "error")
        if key in process_dist:
            return JsonResponse.success("仿真程序已经在运行", "success")
        tess_process = Process(target=start_local_tess_simulator, args=(config_dict,))
        tess_process.start()
        process_dist[key] = {"process": tess_process, "startTime": int(time.time())}
        executor.submit(send_redis_hset, "processInfo", str(i),
                        str({"isUsed": 0,"Using":0,"UsedEnd":0}))

    return JsonResponse.success("仿真进程群启动成功", "success")

@app.route('/jd/training/task/create/', methods=['Post'])
def startLocalSimulator():
    '''
        启动仿真
    '''
    global process_dist
    # 获取仿真配置
    sim_cfg = request.get_json()
    config_dict = {}
    # sim_cfg = {"data": {"interactiveConfig": {"commandChannel": "admin_633_0_5_control",
    #                                           "configure": {"db": 7, "host": "106.120.201.126", "port": 14611,
    #                                                         "pwd": "Wanji@300552!"},
    #                                           "heartChannel": "admin_633_0_5_status",
    #                                           "mainCarChannel": "CDJHS_GKQResult_YK004",
    #                                           "tessngChannel": "admin_633_0_5_data"},
    #                     "networkId": "32c461b9-4897-11ef-a856-0242ac150003", "taskId": "633"},
    #            "timestamp": "1721957378834"}
    # 指令通道  给仿真背景车轨迹信息
    commandChannel = sim_cfg['data']['interactiveConfig']['commandChannel']
    # 仿真心跳数据通道
    heartChannel = sim_cfg['data']['interactiveConfig']['heartChannel']
    # 主车轨迹通道
    mainCarChannel = sim_cfg['data']['interactiveConfig']['mainCarChannel']
    # 仿真轨迹数据通道
    tessngChannel = sim_cfg['data']['interactiveConfig']['tessngChannel']
    taskId = sim_cfg['data']['taskId']
    start_process = False
    configure = sim_cfg['data']['interactiveConfig']['configure']
    config_dict['commandChannel'] = commandChannel
    config_dict['heartChannel'] = heartChannel
    config_dict['mainCarChannel'] = mainCarChannel
    config_dict['tessngChannel'] = tessngChannel
    config_dict['taskId'] = taskId
    config_dict['redisConfigure'] = configure

    # print('启动仿真', "dataChannel:", config_dict['dataChannel'], "commandChannel", config_dict['commandChannel'])
    print('单场景启动仿真', config_dict)
    for i in range(max_process_num):
        processInfo = get_redis_hset("processInfo", str(i))
        # 如果进程在使用中，查询下一个进程是否空闲
        if processInfo['isUsed'] == 1:
            continue
        else:
            start_process = True
            config_dict['isUsed'] = 1
            config_dict['startTime'] = int(time.time())
            config_dict['UsedEnd'] = 0
            config_dict['Using'] = 0
            executor.submit(send_redis_hset, "processInfo", str(i),
                            str(config_dict))
            break
    if start_process:
        return JsonResponse.success("仿真程序启动成功", "success")
    else:
        return JsonResponse.error("仿真程序启动失败，进程群里没有可用的进程", "error")


@app.route('/jd/training/task/stop/', methods=['Post'])
def stopLocalSimulator():
    '''
        启动仿真
    '''
    global process_dist
    # 获取仿真配置
    sim_cfg = request.get_json()
    # sim_cfg = {
    #     "timestamp": 121222,
    #     "data": {
    #         "taskIds": [],
    #         "status": "start"
    #     }
    # }
    # 指令通道  给仿真背景车轨迹信息
    taskIds = sim_cfg['data']['taskIds']

    # print('启动仿真', "dataChannel:", config_dict['dataChannel'], "commandChannel", config_dict['commandChannel'])
    print('场景关闭', sim_cfg)
    for i in range(max_process_num):
        processInfo = get_redis_hset("processInfo", str(i))
        # 如果进程在使用中，查询下一个进程是否空闲
        if processInfo['isUsed'] == 1:
            if processInfo['taskId'] in taskIds or len(taskIds) == 0:
                processInfo['UsedEnd'] = 1
                executor.submit(send_redis_hset, "processInfo", str(i),
                                str(processInfo))
        else:
            continue

    return JsonResponse.success("仿真程序关闭成功", "success")



@app.errorhandler(Exception)
def error_handler(e):
    """
    全局异常捕获
    """
    return JsonResponse.error(msg=str(e))


def runstart():
    app.run(host='0.0.0.0', port=5002)


def listen_process_status():
    """
    监听进程群中的进程状态，若进程启动时间大于设定的最大仿真时间，进程主动关闭并开启新的空白进程等待连接
                       若进程启动时间大于设定的最大仿真时间，进程主动关闭并开启新的空白进程等待连接

    """
    pass


def httpserver():
    # threading.Thread(target=listen_process_status).start()
    runstart()
